package com.thinkit.bigdata.web.service.impl.tag;

import com.google.common.base.Strings;
import com.thinkit.bigdata.core.util.DateFormatUtil;
import com.thinkit.bigdata.core.util.es.ESUtil;
import com.thinkit.bigdata.web.coremet.SystemStatic;
import com.thinkit.bigdata.web.dao.tag.TagManagerMapper;
import com.thinkit.bigdata.web.model.es.audioEs.*;
import com.thinkit.bigdata.web.model.perCenter.PendingTaskModel;
import com.thinkit.bigdata.web.model.result.Constants;
import com.thinkit.bigdata.web.model.result.HtmlResult;
import com.thinkit.bigdata.web.model.sec.User;
import com.thinkit.bigdata.web.model.tag.*;
import com.thinkit.bigdata.web.service.tag.TagManagerService;
import org.apache.shiro.SecurityUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
public class TagManagerServiceImpl implements TagManagerService {
    private static final Logger LOGGER = LoggerFactory.getLogger(TagManagerServiceImpl.class);

    @Resource
    private ESUtil esUtil;

    @Resource
    private TagManagerMapper tagManagerMapper;

    @Override
    public int coutBySerialNumber(String serialNumber) {
        return tagManagerMapper.coutBySerialNumber(serialNumber);
    }

    @Override
    @Transactional
    public HtmlResult addTagAudio(Source source) {
        String audioId = UUID.randomUUID().toString();

        // 获取时间，保证创建时间一致
        Date date = new Date();

        // 插入tag_audio标注语音表
        insertTagAudio(source, audioId);

        // 插入tag_audio_info语音描述信息表
        insertTagAudioInfo(source.getVoiceInfo(), audioId);

        // 插入tag_operate标注轨迹表
        insertTagOperate(audioId);

        // 静音处理
        silenceHandle(audioId, source.getSttInfo().getSilences(), date);

        // 叠音处理
        assHandle(audioId, source.getSttInfo().getInterrupted(), date);

        // 转写结果
        List<SttSentences> sttSentences = source.getSttInfo().getSttSentences();

        if (sttSentences != null && !sttSentences.isEmpty()) {
            // 按照start进行升序排列
            Collections.sort(sttSentences, new Comparator<SttSentences>() {
                public int compare(SttSentences o1, SttSentences o2) {

                    if (o1.getStart() > o2.getStart()) {
                        return 1;
                    }
                    if (o1.getStart() == o2.getStart()) {
                        return 0;
                    }
                    return -1;
                }
            });

            // 语音包含信道信息
            List<Integer> channels = new ArrayList<>();

            // 语音时长
            double dur = source.getVoiceInfo().getHoldDuration();

            for (SttSentences sentences : sttSentences) {
                // 保存角色
                if (sentences.getChannel() != null && !channels.contains(sentences.getChannel())) {
                    channels.add(sentences.getChannel());
                }

                Double endTime = sentences.getEnd();
                // 超出总时长或误差小于0.4
                if (endTime > dur || dur - endTime < 0.4) {
                    endTime = dur;
                    sentences.setEnd(endTime);
                }

                // 插入tag_stt_detail初始详细信息表
                insertTagSttDetail(sentences, audioId, date);

                // 插入tag_detail标注结果详细信息
                insertTagDetail(sentences, audioId, date);
            }

            // 插入tag_stt_global初始全局数据表
            insertTagSttGlobal(audioId, channels);

            // 插入tag_global标注结果全局数据表
            insertTagGlobal(audioId, channels);
        }

        return HtmlResult.success("标注语音添加成功");
    }

    /**
     * 获取登录用户id
     */
    private String getSessionUserId() {
        User user = (User) SecurityUtils.getSubject().getSession().getAttribute(Constants.SESSION_USER_INFO);
        return user == null ? Constants.STT_USER_ID : String.valueOf(user.getId());
    }

    /**
     * 插入tag_audio标注语音表
     */
    private void insertTagAudio(Source source, String audioId) {
        TagAudio tagAudio = new TagAudio();
        tagAudio.setId(audioId);
        tagAudio.setSerialnumber(source.getSerialNumber());
        tagAudio.setFilepath(source.getAudioPath());
        tagAudio.setFilename(source.getAudioPath().substring(source.getAudioPath().lastIndexOf('/') + 1));
        tagAudio.setDuration(Double.valueOf(source.getVoiceInfo().getHoldDuration()));
        tagAudio.setValidduration(0.0d);
        tagAudio.setStorerid(getSessionUserId());
        tagAudio.setInputtime(new Date());
        tagAudio.setState(TagAudio.STATUS_TAG_WAIT);
        tagManagerMapper.insertTagAudio(tagAudio);
    }

    /**
     * 插入tag_audio_info语音描述信息表
     */
    private void insertTagAudioInfo(VoiceInfo voiceInfo, String audioId) {
        TagAudioInfo tagAudioInfo = new TagAudioInfo();
        tagAudioInfo.setAudioid(audioId);
        tagAudioInfo.setProvincecode(voiceInfo.getProvinceCode());
        tagAudioInfo.setCallstarttime(DateFormatUtil.Str2Date(voiceInfo.getCallStartTime(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
        tagAudioInfo.setCallendtime(DateFormatUtil.Str2Date(voiceInfo.getCallEndTime(), DateFormatUtil.yyyy_MM_dd_HH_mm_ss));
        tagAudioInfo.setGroupid(voiceInfo.getGroupId());
        tagAudioInfo.setSeatgroup(voiceInfo.getSeatGroup());
        tagAudioInfo.setSeatid(voiceInfo.getSeatId());
        tagAudioInfo.setSeatname(voiceInfo.getSeatName());
        tagAudioInfo.setCustomernum(voiceInfo.getCustomerNum());
        tagAudioInfo.setSeatnum(voiceInfo.getSeatNum());
        tagAudioInfo.setCalldirection(voiceInfo.getCallDirection());
        tagAudioInfo.setProphonenum(voiceInfo.getProPhoneNum());
        tagAudioInfo.setIseachrecord(Integer.valueOf(voiceInfo.getIsEachRecord()));
        tagAudioInfo.setOnhook(Integer.valueOf(voiceInfo.getOnHook()));
        tagAudioInfo.setCustomerloc(voiceInfo.getCustomerloc());
        tagAudioInfo.setCustomerlevel(voiceInfo.getCustomerLevel());
        tagAudioInfo.setSatisfaction(voiceInfo.getSatisfaction());
        tagAudioInfo.setRecallflag(voiceInfo.getReCallFlag());
        tagAudioInfo.setCustomersign(0);
        tagManagerMapper.insertTagAudioInfo(tagAudioInfo);
    }

    /**
     * 插入tag_stt_detail初始详细信息表
     */
    private void insertTagSttDetail(SttSentences sentences, String audioId, Date date) {
        // 情绪处理
        StringBuilder tagContent = new StringBuilder(sentences.getCentent());
        if (sentences.getEmotion() != null && sentences.getEmotion() == 0) {
            tagContent.append(Constants.ANGRY);
        }
        TagSttDetail tagSttDetail = new TagSttDetail();
        tagSttDetail.setId(UUID.randomUUID().toString());
        tagSttDetail.setAudioid(audioId);
        tagSttDetail.setStarttime(sentences.getStart());
        tagSttDetail.setEndtime(sentences.getEnd());
        tagSttDetail.setCreatetime(date);
        tagSttDetail.setTagcontent(String.valueOf(tagContent));
        tagSttDetail.setValid(Constants.IS_NOT_VALID);
        tagSttDetail.setTagspeaker(getTagSpeaker(sentences.getChannel()));
        tagSttDetail.setChannel(sentences.getChannel());
        tagSttDetail.setSpeed(sentences.getSpeed());
        tagSttDetail.setEnergy(sentences.getEnergy());
        tagSttDetail.setEmotion(sentences.getEmotion());
        tagManagerMapper.insertTagSttDetail(tagSttDetail);
    }

    /**
     * 插入tag_detail标注结果详细信息
     */
    private void insertTagDetail(SttSentences sentences, String audioId, Date date) {
        // 情绪处理
        StringBuilder tagContent = new StringBuilder(sentences.getCentent());
        if (sentences.getEmotion() != null && sentences.getEmotion() == 0) {
            tagContent.append(Constants.ANGRY);
        }
        TagDetail tagDetail = new TagDetail();
        tagDetail.setId(UUID.randomUUID().toString());
        tagDetail.setAudioid(audioId);
        tagDetail.setStarttime(sentences.getStart());
        tagDetail.setEndtime(sentences.getEnd());
        tagDetail.setCreatetime(date);
        tagDetail.setTagcontent(String.valueOf(tagContent));
        tagDetail.setValid(Constants.IS_NOT_VALID);
        tagDetail.setTagspeaker(getTagSpeaker(sentences.getChannel()));
        tagDetail.setTagtime(date);
        tagDetail.setTagstatus(TagDetail.STATUS_TAG);
        tagDetail.setChannel(sentences.getChannel());
        tagDetail.setSpeed(sentences.getSpeed());
        tagDetail.setEnergy(sentences.getEnergy());
        tagDetail.setEmotion(sentences.getEmotion());
        tagManagerMapper.insertTagDetail(tagDetail);
    }

    /**
     * 插入tag_operate标注轨迹表
     */
    private void insertTagOperate(String audioId) {
        TagOperate tagOperate = new TagOperate();
        tagOperate.setId(UUID.randomUUID().toString());
        tagOperate.setAudioid(audioId);
        tagOperate.setOperatorid(getSessionUserId());
        tagOperate.setOperatetime(new Date());
        tagOperate.setOpertype(TagOperate.OPERTYPE_ADD);
        tagOperate.setOriginalstate(TagAudio.STATUS_TAG_WAIT);
        tagOperate.setNewstate(TagAudio.STATUS_TAG_WAIT);
        tagOperate.setContent(null);
        tagManagerMapper.insertTagOperate(tagOperate);
    }

    /**
     * 插入tag_stt_global初始全局数据表
     */
    private void insertTagSttGlobal(String audioId, List<Integer> channels) {
        Map map = getGlobalInfo(channels);
        TagSttGlobal tagSttGlobal = new TagSttGlobal();
        tagSttGlobal.setAudioid(audioId);
        tagSttGlobal.setLanguages(String.valueOf(map.get("languages")));
        tagSttGlobal.setArticulationtype(Constants.ARTICULATION_ZRYY);
        tagSttGlobal.setSpeakers(String.valueOf(map.get("speakers")));
        tagSttGlobal.setRoles(String.valueOf(map.get("roles")));
        tagSttGlobal.setInputtime(new Date());
        tagManagerMapper.insertTagSttGlobal(tagSttGlobal);
    }

    /**
     * 插入tag_global标注结果全局数据表
     */
    private void insertTagGlobal(String audioId, List<Integer> channels) {
        Map map = getGlobalInfo(channels);
        TagGlobal tagGlobal = new TagGlobal();
        tagGlobal.setAudioid(audioId);
        tagGlobal.setLanguages(String.valueOf(map.get("languages")));
        tagGlobal.setArticulationtype(Constants.ARTICULATION_ZRYY);
        tagGlobal.setSpeakers(String.valueOf(map.get("speakers")));
        tagGlobal.setRoles(String.valueOf(map.get("roles")));
        tagGlobal.setInputtime(new Date());
        tagGlobal.setRemark("新增");
        tagManagerMapper.insertTagGlobal(tagGlobal);
    }

    /**
     * 静音信息处理
     */
    private void silenceHandle(String audioId, List<Silence> silences, Date date) {
        if (silences != null && !silences.isEmpty()) {
            for (Silence silence : silences) {
                if (silence.getChannel() != null && silence.getChannel() == 2) {
                    SttSentences stt = new SttSentences();
                    stt.setStart(silence.getStart());
                    stt.setEnd(silence.getEnd());
                    stt.setCentent(Constants.SILENCE);
                    stt.setSpeed(0D);
                    stt.setEnergy(0D);

                    // 插入tag_stt_detail初始详细信息表
                    insertTagSttDetail(stt, audioId, date);

                    // 插入tag_detail标注结果详细信息
                    insertTagDetail(stt, audioId, date);
                }
            }
        }
    }

    /**
     * 叠音信息处理
     */
    private void assHandle(String audioId, List<AssInfo> assInfos, Date date) {
        if (assInfos != null && !assInfos.isEmpty()) {
            for (AssInfo assInfo : assInfos) {
                SttSentences stt = new SttSentences();
                stt.setStart(assInfo.getStart());
                stt.setEnd(assInfo.getEnd());
                stt.setCentent(Constants.OVERLAP);
                stt.setSpeed(0D);
                stt.setEnergy(0D);

                // 插入tag_stt_detail初始详细信息表
                insertTagSttDetail(stt, audioId, date);

                // 插入tag_detail标注结果详细信息
                insertTagDetail(stt, audioId, date);
            }
        }
    }

    /**
     * 根据信道返回说话人标识
     *
     * @param channel
     * @return
     */
    public static String getTagSpeaker(Integer channel) {
        String tagSpeaker = null;
        if (channel != null) {
            switch (channel) {
                case 0:
                    tagSpeaker = Constants.TAG_SPEAKER_SEAT;
                    break;
                case 1:
                    tagSpeaker = Constants.TAG_SPEAKER_USER;
                    break;
                default:
                    tagSpeaker = null;
            }
        }
        return tagSpeaker;
    }

    /**
     * 根据信道返回全局信息
     *
     * @param channels -
     * @return -
     */
    public static Map<String, Object> getGlobalInfo(List<Integer> channels) {
        Map<String, Object> globalInfoMap = new HashMap<>();
        globalInfoMap.put("languages", "");
        globalInfoMap.put("speakers", "");
        globalInfoMap.put("roles", "");
        if (!channels.isEmpty()) {
            StringBuilder lb = new StringBuilder();
            StringBuilder sb = new StringBuilder();
            StringBuilder rb = new StringBuilder();
            for (int i = 0; i < channels.size(); i++) {
                if (channels.get(i) == 0) {
                    lb.append(i + 1).append(" ").append(Constants.DEFAULT_LANGUAGES).append(",");
                    sb.append(i + 1).append(" ").append(",");
                    rb.append(i + 1).append(" ").append(Constants.DEFAULT_ROLES_ZX).append(",");
                } else if (channels.get(i) == 1) {
                    lb.append(i + 1).append(" ").append(Constants.DEFAULT_LANGUAGES).append(",");
                    sb.append(i + 1).append(" ").append(",");
                    rb.append(i + 1).append(" ").append(Constants.DEFAULT_ROLES_KH).append(",");
                }
            }
            // 去除末尾“,”
            String languages = lb.substring(0, lb.length() - 1);
            String speakers = sb.substring(0, sb.length() - 1);
            String roles = rb.substring(0, rb.length() - 1);
            globalInfoMap.put("languages", languages);
            globalInfoMap.put("speakers", speakers);
            globalInfoMap.put("roles", roles);
        }
        return globalInfoMap;
    }

    /**
     * es查询所有语音流水号
     */
    @Override
    public List<PendingTaskModel> searchData(HttpServletRequest request) {
        String logTxt = "【语音批量导入Impl】";
        LOGGER.info(logTxt);
        String pageNum = request.getParameter("pageNum");//起始页
        String pageSize = request.getParameter("pageSize");//每页条数
        String sortName = request.getParameter("sortName");//排序名
        String sortOrder = request.getParameter("sortOrder");//排序顺序
        BoolQueryBuilder boolQuery = getQuery(logTxt, request);
        String[] includes = new String[]
                {
                        "serialNumber"
                };
        List<String> docList = SystemStatic.crud.queryMapQBuilderRetRuleAndWork(
                SystemStatic.AUDIO_ES_INDEX,
                SystemStatic.AUDIO_ES_TYPE,
                Integer.parseInt(pageNum),
                Integer.parseInt(pageSize),
                boolQuery,
                SystemStatic.crud.formatCloumn(sortName, SystemStatic.AUDIO_ES_INDEX),
                sortOrder,
                includes
        );
        LOGGER.info(logTxt + "获取数据条数为：" + docList.size());
        return esUtil.formatModelSerialNumber(docList);
    }

    /**
     * 生成查询条件
     */
    @Override
    public BoolQueryBuilder getQuery(String logTxt, HttpServletRequest request) {
        String provinceCode = request.getParameter("provinceCode");//省份
        String inputTimeBegin = request.getParameter("inputTimeBegin");//入库时间
        String inputTimeEnd = request.getParameter("inputTimeEnd");//入库时间
        LOGGER.info(logTxt + "provinceCode = " + provinceCode);
        LOGGER.info(logTxt + "inputTimeBegin = " + inputTimeBegin);
        LOGGER.info(logTxt + "inputTimeEnd = " + inputTimeEnd);
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (!Strings.isNullOrEmpty(provinceCode)) {
            boolQuery.must(QueryBuilders.matchQuery("voiceInfo.provinceCode", provinceCode));
        }
        if (!Strings.isNullOrEmpty(inputTimeBegin)) {
            boolQuery.must(QueryBuilders.rangeQuery("voiceInfo.inputTime").gte(inputTimeBegin));
        }
        if (!Strings.isNullOrEmpty(inputTimeEnd)) {
            boolQuery.must(QueryBuilders.rangeQuery("voiceInfo.inputTime").lte(inputTimeEnd));
        }
        //系统转写成功的
        boolQuery.must(QueryBuilders.termsQuery("voiceInfo.proStatus", new int[]{2, 4, 5, 6}));
        return boolQuery;
    }

}
